home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 2
/
Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso
/
Aminet
/
comm
/
term
/
term34Source.lha
/
termSaveWindow.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-16
|
14KB
|
681 lines
/*
** termSaveWindow.c
**
** Support routines for saving IFF-ILBM files
**
** Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
** All Rights Reserved
*/
#include "termGlobal.h"
/* Current compression mode. */
#define DUMP 0
#define RUN 1
/* ByteRun compression data. */
#define MINRUN 3
#define MAXRUN 128
#define MAXDAT 128
/* Chunk types. */
#define ID_ILBM MAKE_ID('I','L','B','M')
#define ID_ANNO MAKE_ID('A','N','N','O')
#define ID_BMHD MAKE_ID('B','M','H','D')
#define ID_CMAP MAKE_ID('C','M','A','P')
#define ID_CAMG MAKE_ID('C','A','M','G')
#define ID_BODY MAKE_ID('B','O','D','Y')
/* Masking technique. */
#define mskNone 0
/* Compression techniques. */
#define cmpNone 0
#define cmpByteRun1 1
/* A bitmap header. */
typedef struct
{
UWORD w,h; /* raster width & height in pixels */
WORD x,y; /* position for this image */
UBYTE nPlanes; /* # source bitplanes */
UBYTE masking; /* masking technique */
UBYTE compression; /* compression algorithm */
UBYTE pad1; /* UNUSED. For consistency, put 0 here.*/
UWORD transparentColor; /* transparent "color number" */
UBYTE xAspect,yAspect; /* aspect ratio, a rational number x/y */
WORD pageWidth,pageHeight; /* source "page" size in pixels */
} BitMapHeader;
/* A single 8-bit colour register. */
typedef struct
{
UBYTE red, /* red component, 0..255 */
green, /* green component, 0..255 */
blue; /* blue component, 0..255 */
} ColorRegister;
/* Local packer data. */
STATIC LONG PackedBytes;
STATIC BYTE Buffer[MAXDAT + 1];
/* PutDump(register PLANEPTR Destination,register LONG Count):
*
* Output a byte dump.
*/
STATIC PLANEPTR __regargs
PutDump(register PLANEPTR Destination,register LONG Count)
{
register PLANEPTR Source = Buffer;
*Destination++ = Count - 1;
PackedBytes += Count + 1;
while(Count--)
*Destination++ = *Source++;
return(Destination);
}
/* PutRun(register PLANEPTR Destination,LONG Count,WORD Char):
*
* Output a byte run.
*/
STATIC PLANEPTR __regargs
PutRun(register PLANEPTR Destination,LONG Count,WORD Char)
{
*Destination++ = -(Count - 1);
*Destination++ = Char;
PackedBytes += 2;
return(Destination);
}
/* PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize):
*
* Pack a row of bitmap data using ByteRun compression,
* based on the original "EA IFF 85" pack.c example code.
*/
STATIC LONG __regargs
PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize)
{
register PLANEPTR Source = *SourcePtr;
WORD Buffered = 1,
RunStart = 0;
BYTE Mode = DUMP,
LastChar,
Char;
PackedBytes = 0;
Buffer[0] = LastChar = Char = *Source++;
RowSize--;
while(RowSize--)
{
Buffer[Buffered++] = Char = *Source++;
if(Mode)
{
if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
{
Destination = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
Buffer[0] = Char;
Buffered = 1;
RunStart = 0;
Mode = DUMP;
}
}
else
{
if(Buffered > MAXDAT)
{
Destination = PutDump(Destination,Buffered - 1);
Buffer[0] = Char;
Buffered = 1;
RunStart = 0;
}
else
{
if(Char == LastChar)
{
if(Buffered - RunStart >= MINRUN)
{
if(RunStart)
Destination = PutDump(Destination,RunStart);
Mode = RUN;
}
else
{
if(!RunStart)
Mode = RUN;
}
}
else
RunStart = Buffered - 1;
}
}
LastChar = Char;
}
if(Mode)
PutRun(Destination,Buffered - RunStart,LastChar);
else
PutDump(Destination,Buffered);
*SourcePtr = Source;
return(PackedBytes);
}
/* PutANNO(struct IFFHandle *Handle):
*
* Output `ANNO' chunk.
*/
STATIC BYTE __regargs
PutANNO(struct IFFHandle *Handle)
{
extern UBYTE VersTag[];
WORD Len;
Len = strlen(&VersTag[1]);
/* Push the `ANNO' chunk on the stack. */
if(!PushChunk(Handle,0,ID_ANNO,Len))
{
/* Write the creator string. */
if(WriteChunkBytes(Handle,&VersTag[1],Len) == Len)
{
/* Pop the `ANNO' chunk. */
if(!PopChunk(Handle))
return(TRUE);
}
}
return(FALSE);
}
/* PutBMHD():
*
* Output `BMHD' chunk.
*/
STATIC BYTE __regargs
PutBMHD(struct IFFHandle *Handle,struct Window *Window,UBYTE Compression,LONG Left,LONG Top,LONG Width,LONG Height)
{
struct DisplayInfo DisplayInfo;
/* Get the display aspect ratio. */
if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,GetVPModeID(&Window -> WScreen -> ViewPort)))
{
BitMapHeader Header;
/* Fill in the bitmap header. */
Header . w = Width;
Header . h = Height;
Header . pageWidth = Window -> WScreen -> Width;
Header . pageHeight = Window -> WScreen -> Height;
Header . x = Left;
Header . y = Top;
Header . nPlanes = Window -> WScreen -> RastPort . BitMap -> Depth;
Header . masking = mskNone;
Header . compression = Compression;
Header . pad1 = 0;
Header . transparentColor = 0;
Header . xAspect = DisplayInfo . Resolution . x;
Header . yAspect = DisplayInfo . Resolution . y;
/* Push the `BMHD' chunk on the stack. */
if(!PushChunk(Handle,0,ID_BMHD,sizeof(BitMapHeader)))
{
/* Write the bitmap header. */
if(WriteChunkBytes(Handle,&Header,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
{
/* Pop the `BMHD' chunk. */
if(!PopChunk(Handle))
return(TRUE);
}
}
}
return(FALSE);
}
/* PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort):
*
* Output `CMAP' chunk, only 4-bit colour registers
* are supported so far.
*/
STATIC BYTE __regargs
PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort)
{
/* Push the `CMAP' chunk on the stack. */
if(!PushChunk(Handle,0,ID_CMAP,3 * VPort -> ColorMap -> Count))
{
ColorRegister Colour;
LONG i;
ULONG Value,
R,G,B;
/* Read and convert all the
* ColorMap entries (4 bit colour
* components only).
*/
for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
{
/* Read colour value. */
Value = GetRGB4(VPort -> ColorMap,i);
/* Split the value into components. */
R = (Value >> 8) & 0xF;
G = (Value >> 4) & 0xF;
B = (Value ) & 0xF;
/* Store the colour components. */
Colour . red = (R << 4) | R;
Colour . green = (G << 4) | G;
Colour . blue = (B << 4) | B;
/* Write the colours. */
if(WriteChunkBytes(Handle,&Colour,3) != 3)
return(FALSE);
}
/* Pop the `CMAP' chunk. */
if(!PopChunk(Handle))
return(TRUE);
}
return(FALSE);
}
/* PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort):
*
* Output `CAMG' chunk.
*/
STATIC BYTE __regargs
PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort)
{
if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
{
ULONG ViewModes = GetVPModeID(VPort);
if(WriteChunkBytes(Handle,&ViewModes,sizeof(ULONG)) == sizeof(ULONG))
{
if(!PopChunk(Handle))
return(TRUE);
}
}
return(FALSE);
}
/* PutBODY(struct IFFHandle *Handle)
*
* Output `BODY' chunk.
*/
STATIC BYTE __regargs
PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap,UBYTE Compression)
{
BYTE Success = FALSE;
PLANEPTR *Planes;
/* Allocate temporary bitplane pointers. */
if(Planes = (PLANEPTR *)AllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR))
{
register LONG i;
/* Copy the bitplane pointers. */
for(i = 0 ; i < BitMap -> Depth ; i++)
Planes[i] = BitMap -> Planes[i];
/* Are we to compress the data? */
if(Compression == cmpByteRun1)
{
PLANEPTR PackBuffer;
/* Allocate line compression buffer. */
if(PackBuffer = (PLANEPTR)AllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY))
{
/* Push the `BODY' chunk on the stack. */
if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
{
register LONG PackedBytes,
j;
/* So far, we are quite successful,
* any write access to fail will
* cause `Success' to drop to FALSE.
*/
Success = TRUE;
/* Compress all the rows. */
for(i = 0 ; Success && i < BitMap -> Rows ; i++)
{
/* Compress all the planes. */
for(j = 0 ; Success && j < BitMap -> Depth ; j++)
{
/* Do the compression. */
PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
/* Write the compressed data. */
if(WriteChunkBytes(Handle,PackBuffer,PackedBytes) != PackedBytes)
Success = FALSE;
}
}
/* Pop the `BODY' chunk. */
if(PopChunk(Handle))
Success = FALSE;
}
/* Free the line compression buffer. */
FreeVec(PackBuffer);
}
}
else
{
/* Push the `BODY' chunk on the stack. */
if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
{
register LONG j;
/* So far, we are quite successful,
* any write access to fail will
* cause `Success' to drop to FALSE.
*/
Success = TRUE;
/* Compress all the rows. */
for(i = 0 ; Success && i < BitMap -> Rows ; i++)
{
/* Compress all the planes. */
for(j = 0 ; Success && j < BitMap -> Depth ; j++)
{
/* Write the row. */
if(WriteChunkBytes(Handle,Planes[j],BitMap -> BytesPerRow) != BitMap -> BytesPerRow)
Success = FALSE;
else
Planes[j] += BitMap -> BytesPerRow;
}
}
/* Pop the `BODY' chunk. */
if(PopChunk(Handle))
Success = FALSE;
}
}
/* Free the temporary bitplane pointers. */
FreeVec(Planes);
}
/* Return the result. */
return(Success);
}
/* SaveWindow(STRPTR Name,struct Window *Window):
*
* Save the contents of a window to a file.
*/
BYTE
SaveWindow(STRPTR Name,struct Window *Window)
{
struct RastPort *RPort;
BYTE Success = FALSE,
NewFile = FALSE,
Locked = TRUE;
LockLayerRom(Window -> RPort -> Layer);
/* Allocate a dummy rastport, we will need only
* to copy the contents of the window into the
* bitmap.
*/
if(RPort = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
{
struct BitMap *BitMap;
/* Initialize the rastport with defaults. */
InitRastPort(RPort);
/* Allocate a bitmap. */
if(BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY))
{
LONG Width = Window -> Width - (Window -> BorderLeft + Window -> BorderRight),
Height = Window -> Height - (Window -> BorderTop + Window -> BorderBottom),
Left = Window -> LeftEdge + Window -> BorderLeft,
Top = Window -> TopEdge + Window -> BorderTop;
WORD i;
/* Put it into the rastport. */
RPort -> BitMap = BitMap;
/* Initialize it with the window dimensions. */
InitBitMap(BitMap,Window -> WScreen -> RastPort . BitMap -> Depth,Width,Height);
/* Flag success so any allocation
* to fail in the bitplane allocation
* loop will indicate failure.
*/
Success = TRUE;
/* Allocate all the bitplanes necessary. */
for(i = 0 ; Success && i < BitMap -> Depth ; i++)
{
if(!(BitMap -> Planes[i] = AllocRaster(Width,Height)))
Success = FALSE;
}
/* Did we get all the planes we wanted? */
if(Success)
{
struct IFFHandle *Handle;
/* Copy the window contents to the
* local bitmap.
*/
ClipBlit(Window -> RPort,Window -> BorderLeft,Window -> BorderTop,RPort,0,0,Width,Height,MINTERM_COPY);
/* Release the lock on the window layer. */
UnlockLayerRom(Window -> RPort -> Layer);
Locked = FALSE;
/* Reset the success indicator. */
Success = FALSE;
/* Allocate an iff handle. */
if(Handle = AllocIFF())
{
/* Open a file for write access. */
if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
{
/* Remember that we succeeded
* in creating a new file.
*/
NewFile = TRUE;
/* Tell iffparse.library that it's
* a plain AmigaDOS file handle.
*/
InitIFFasDOS(Handle);
/* Open the file for writing. */
if(!OpenIFF(Handle,IFFF_WRITE))
{
/* Push parent chunk on the
* stack.
*/
if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
{
/* Output all the chunk data. */
if(PutANNO(Handle))
{
UBYTE Compression;
/* Don't compress the bitmap if
* isn't really worth it.
*/
if(BitMap -> BytesPerRow > 4)
Compression = cmpByteRun1;
else
Compression = cmpNone;
if(PutBMHD(Handle,Window,Compression,Left,Top,Width,Height))
{
if(PutCMAP(Handle,&Window -> WScreen -> ViewPort))
{
if(PutCAMG(Handle,&Window -> WScreen -> ViewPort))
{
if(PutBODY(Handle,BitMap,Compression))
{
/* Pop the parent chunk
* from the stack.
*/
if(!PopChunk(Handle))
Success = TRUE;
}
}
}
}
}
}
/* Close the iff handle. */
CloseIFF(Handle);
}
/* Close the file. */
if(!Close(Handle -> iff_Stream))
Success = FALSE;
}
/* Free the iff handle. */
FreeIFF(Handle);
}
}
/* Free all bitplanes. */
for(i = 0 ; i < BitMap -> Depth ; i++)
{
if(BitMap -> Planes[i])
FreeRaster(BitMap -> Planes[i],Width,Height);
}
/* Free the bitmap. */
FreeVec(BitMap);
}
/* Free the rastport. */
FreeVec(RPort);
}
/* Release the window layer in case it is still locked. */
if(Locked)
UnlockLayerRom(Window -> RPort -> Layer);
/* If successful, clear the `executable' bit. */
if(Success)
{
AddProtection(Name,FIBF_EXECUTE);
if(Config -> MiscConfig -> CreateIcons)
AddIcon(CaptureName,FILETYPE_PICTURE,TRUE);
}
else
{
/* Delete the remains of the file. */
if(NewFile)
DeleteFile(Name);
}
/* Return the result. */
return(Success);
}